package com.rivues.module.platform.web.handler;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.hadoop.hdfs.web.JsonUtil;
import org.apache.solr.JSONTestUtil;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.noggit.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.druid.support.json.JSONUtils;
import com.rivues.core.RivuDataContext;
import com.rivues.module.platform.web.auth.AuthInterface;
import com.rivues.module.platform.web.auth.AuthInterfaceImpl;
import com.rivues.module.platform.web.bean.TaskInfo;
import com.rivues.module.platform.web.model.AnalyzerReport;
import com.rivues.module.platform.web.model.AnalyzerReportModel;
import com.rivues.module.platform.web.model.Auth;
import com.rivues.module.platform.web.model.Cube;
import com.rivues.module.platform.web.model.CubeLevel;
import com.rivues.module.platform.web.model.CubeMeasure;
import com.rivues.module.platform.web.model.CubeMetadata;
import com.rivues.module.platform.web.model.DataDic;
import com.rivues.module.platform.web.model.Database;
import com.rivues.module.platform.web.model.Dimension;
import com.rivues.module.platform.web.model.JobDetail;
import com.rivues.module.platform.web.model.PublishedCube;
import com.rivues.module.platform.web.model.ReportFilter;
import com.rivues.module.platform.web.model.TableDir;
import com.rivues.module.platform.web.model.TableProperties;
import com.rivues.module.platform.web.model.TableTask;
import com.rivues.module.platform.web.model.TypeCategory;
import com.rivues.module.platform.web.model.User;
import com.rivues.module.report.web.model.PublishedReport;
import com.rivues.util.RivuTools;
import com.rivues.util.data.CubeData;
import com.rivues.util.data.ReportData;
import com.rivues.util.iface.authz.UserAuthzFactory;
import com.rivues.util.iface.cube.CubeFactory;
import com.rivues.util.iface.report.ReportFactory;
import com.rivues.util.local.LocalTools;
import com.rivues.util.serialize.JSON;
import com.rivues.util.service.cache.CacheHelper;

@Controller  
@RequestMapping("/{orgi}/api/report")  
public class ReportAPIController extends Handler{
	private final Logger log = LoggerFactory.getLogger(ReportAPIController.class); 
	/**
	 * 
	 * @param request
	 * @param response
	 * @param orgi
	 * @param authzUser用户名
	 * @param authzPassword用户密码
	 * @param reportid报表id
	 * @param datacount查询数量
	 * @throws Exception
	 */
	@RequestMapping(value="/findReportData" , name="findReportData" , type="api",subtype="reportapi")
	public void findReportData(HttpServletRequest request ,HttpServletResponse response,@PathVariable String orgi,@Valid String authzUser,@Valid String authzPassword,@Valid String reportid,@Valid int datacount) throws Exception {
    	
    	response.setContentType("text/html;charset=UTF-8");
    	PrintWriter writer = response.getWriter();
    	int count = super.getService().getCountByCriteria(DetachedCriteria.forClass(PublishedReport.class).add(Restrictions.eq("id", reportid))) ;
    	boolean authz = UserAuthzFactory.getInstance(orgi).authentication(authzUser,authzPassword,orgi) ;
    	if(!authz){
    		writer.write("authentication_faild");
    	}else if(count<=0){
    		writer.write("noreport");
    	}else{
    		PublishedReport report = ReportFactory.getReportInstance().getReportByID(super.getUser(request), orgi, reportid) ;
        	AnalyzerReport analyzerReport = report.getReport() ;
        	AnalyzerReportModel reportModel = null ;
        	if(analyzerReport.getModel().size()>0){
        		for(AnalyzerReportModel model : analyzerReport.getModel()){
        			if(reportModel==null){
        				reportModel = model ;
        				break;
        			}
        		}
        	}
        	if(reportModel != null){
    	    	/**
    	    	 * 以下代码用于
    	    	 */
    	    	for(ReportFilter reportFilter : analyzerReport.getFilters()){
    	    		if(RivuDataContext.ReportCompareEnum.RANGE.toString().equals(reportFilter.getValuefiltertype())){
    	    			if(request.getParameter(reportFilter.getCode()+"_start")!=null && request.getParameter(reportFilter.getCode()+"_end")!=null){
    		    			if(RivuDataContext.FilterConValueEnum.AUTO.toString().equals(reportFilter.getConvalue())){
    		    				String start = request.getParameter(reportFilter.getCode()+"_start")!=null ? request.getParameter(reportFilter.getCode()+"_start") : "" ;
    		    				String end = request.getParameter(reportFilter.getCode()+"_end")!=null ? request.getParameter(reportFilter.getCode()+"_end") : "" ;
    		    				if((start.length() - start.replaceAll(".", "").length()) != (end.length() - end.replaceAll(".", "").length())){
    		    					continue ;
    		    				}
    		    			}
    		    			reportFilter.setRequeststartvalue(request.getParameter(reportFilter.getCode()+"_start")) ;
    		    			reportFilter.setRequestendvalue(request.getParameter(reportFilter.getCode()+"_end")) ;
    	    			}
    	    		}else{
    		    		if(request.getParameter(reportFilter.getCode())!=null){
    		    			reportFilter.setRequestvalue(request.getParameter(reportFilter.getCode())) ;
    		    		}
    	    		}
    	    	}
        	}
        	ReportData reportData = RivuTools.getReportData(analyzerReport, request, reportModel,0, datacount);
        	JsonConfig config = new JsonConfig();
			config.setExcludes(new String[] {"row","col"});
        	writer.print(JSONObject.fromObject(reportData,config));
    	}
    	
	}	

    @RequestMapping(value="/reportpublish" , name="reportpublish" , type="api",subtype="reportapi")
	public void reportpublish(HttpServletRequest request ,HttpServletResponse response,@PathVariable String orgi,@Valid String isRecover,@Valid String reportjson) throws Exception {
    	reportjson = RivuTools.decryption(reportjson);
    	response.setContentType("text/html;charset=UTF-8");
    	
    	PrintWriter writer = response.getWriter();
    	PublishedReport report  = JSON.parseObject(reportjson , PublishedReport.class);
    	PublishedReport rpt = ReportFactory.getReportInstance().getReportByID(super.getUser(request), orgi, report.getId());
		report.setPublishedtype("published");
		report.setStatus("available");
		report.setReportversion(rpt.getReportversion());
    	if(rpt==null){
    		ReportFactory.getReportInstance().createReport(report, super.getUser(request));
    	}else{
    		if(!"yes".equals(isRecover)){
    			report.setReportversion(rpt.getReportversion()+1);
    		}
    		ReportFactory.getReportInstance().updateReport(report, super.getUser(request));
    	}
    	writer.write("successful");
	}
    
    
    
    
    @RequestMapping(value="/reportimporto" , name="reportimporto" , type="api" , subtype="reportapi")  
    public void reportimporto(HttpServletRequest request , HttpServletResponse response,@PathVariable String orgi ,@RequestParam MultipartFile file,@Valid String username,@Valid String password , @Valid String command) throws Exception{  
		
		File fTemp = null;
		try {
			if(username!=null || super.getUser(request)!=null){
				if(super.getUser(request) == null){
					boolean authz = UserAuthzFactory.getInstance(orgi).authentication(username,password,orgi) ;
					if(!authz){//认证不通过
						throw new Exception(LocalTools.getMessage("E_REPORT_10010019"));
					}
				}
				fTemp = File.createTempFile("reports", ".zip"); 
				FileOutputStream writeFile = new FileOutputStream(fTemp); 
				writeFile.write(file.getBytes());
				ZipFile zf = new ZipFile(fTemp);
				ZipEntry entry = null;
				Object dataObject = null ;
				InputStream inputStream = null;
				for(Enumeration<?> entries = zf.getEntries(); entries.hasMoreElements();){
	                entry = (ZipEntry)entries.nextElement(); 
	                inputStream = zf.getInputStream(entry);
	                byte[] buf1=new byte[1024];
	                StringBuffer sb= new StringBuffer();
	                int len = 0 ;
	                while((len = inputStream.read(buf1))>0){
	                    //out.write(buf1,0,len);
	                    sb.append(new String(buf1 , 0 , len));
	                }
	                if(entry.getName().endsWith(".rptdic")){
	                	if(!"delete".equals(command)){
		                	dataObject = JSON.parseObject(sb.toString().trim() , DataDic.class);
		                	executeImportCommand(dataObject , command);
	                	}
	                }
	                if(entry.getName().endsWith(".cubdic")){
	                	if(!"delete".equals(command)){
	                		dataObject =  JSON.parseObject(sb.toString().trim() , TypeCategory.class);
		                	executeImportCommand(dataObject , command);
	                	}
	                }
	                if(entry.getName().endsWith(".pcub")){
	                	if(!"delete".equals(command)){
	                		dataObject =  JSON.parseObject(sb.toString().trim() , PublishedCube.class);
		                	executeImportCommand(dataObject , command);
	                	}
	                }
//	                if(entry.getName().endsWith(".cub")){
//	                	Cube cube = JSON.parseObject(sb.toString().trim() , Cube.class);
//	                	List<CubeMetadata> metadata = cube.getMetadata();
//	        			List<Dimension> dimension = cube.getDimension();
//	        			List<CubeMeasure> measure = cube.getMeasure();
//	                	executeImportCommand(cube , command);
//	                	
//	        			for (int j = 0; j < metadata.size(); j++) {
//	        				metadata.get(j).setCube(cube.getId());
//	        				executeImportCommand(metadata.get(j) , command);
//	        			}
//
//	        			for (int j = 0; j < dimension.size(); j++) {
//	        				List<CubeLevel> levels = dimension.get(j).getCubeLevel();
//	        				dimension.get(j).setCubeid(cube.getId());
//	        				executeImportCommand(dimension.get(j) , command);
//	        				for (int k = 0; k < levels.size(); k++) {
//	        					levels.get(k).setDimid(dimension.get(j).getId());
//	        					levels.get(k).setCubeid(cube.getId());
//	        					executeImportCommand(levels.get(k) , command);
//	        				}
//	        			}
//
//	        			for (int j = 0; j < measure.size(); j++) {
//	        				measure.get(j).setCubeid(cube.getId());
//	        				executeImportCommand(measure.get(j) , command);
//	        			}
//	                }
	                if(entry.getName().endsWith(".rpt")){
	                	dataObject = JSON.parseObject(sb.toString().trim() , PublishedReport.class);
		                ((PublishedReport)dataObject).setReportcontent(URLDecoder.decode(((PublishedReport)dataObject).getReportcontent()==null?"":((PublishedReport)dataObject).getReportcontent()));
		                executeImportCommand(dataObject , command);
	                }
	       
	                if(entry.getName().endsWith(".auth")){
	                	dataObject = JSON.parseObject(sb.toString().trim() , Auth.class);
		                executeImportCommand(dataObject , command);
	                }
	             
	                
	                if(entry.getName().endsWith(".ds")){
	                	dataObject = JSON.parseObject(sb.toString().trim() , Database.class);
	                	if(!"delete".equals(command)){
	                		Database db = (Database)dataObject;
	                		
	                		for (TableDir dir : db.getTabledirs()) {//保存目录
	                			executeImportCommand(dir , command);
							}
	                		
	                		for (TableTask table : db.getTabletasks()) {//保存表
	                			executeImportCommand(table , command);
	                			for (TableProperties properties : table.getTableproperty()) {
	                				executeImportCommand(properties , command);
	                			}
	                			
							}
	                		executeImportCommand(db , command);
	                	}
	                }
	                inputStream.close(); 
	           } 
			   writeFile.close();
	           zf.close(); 
			}else{
				throw new Exception(LocalTools.getMessage("E_REPORT_10010019"));
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
//			throw e;
			e.printStackTrace();
			response.setContentType("text/html,charset=UTF-8") ;
			response.setCharacterEncoding("UTF-8") ;
			response.getOutputStream().write(e.getMessage().getBytes()) ;
		}finally{
			if(fTemp!=null){
				fTemp.delete();
			}
		}
    }
    
    @RequestMapping(value="/taskimporto" , name="taskimporto" , type="api" , subtype="reportapi")  
    public int taskimporto(HttpServletRequest request , HttpServletResponse response,@PathVariable String orgi ,@RequestParam MultipartFile file,@Valid String username,@Valid String password , @Valid String command) throws Exception{  
		int count = 0;
		File fTemp = null;
		try {
			if(username!=null || super.getUser(request)!=null){
				if(super.getUser(request) == null){
					boolean authz = UserAuthzFactory.getInstance(orgi).authentication(username,password,orgi) ;
					if(!authz){//认证不通过
						throw new Exception(LocalTools.getMessage("E_REPORT_10010019"));
					}
				}
				fTemp = File.createTempFile("reports", ".zip"); 
				FileOutputStream writeFile = new FileOutputStream(fTemp); 
				writeFile.write(file.getBytes());
				ZipFile zf = new ZipFile(fTemp);
				ZipEntry entry = null;
				Object dataObject = null ;
				InputStream inputStream = null;
				for(Enumeration<?> entries = zf.getEntries(); entries.hasMoreElements();){
	                entry = (ZipEntry)entries.nextElement(); 
	                inputStream = zf.getInputStream(entry);
	                byte[] buf1=new byte[1024];
	                StringBuffer sb= new StringBuffer();
	                int len = 0 ;
	                while((len = inputStream.read(buf1))>0){
	                    //out.write(buf1,0,len);
	                    sb.append(new String(buf1 , 0 , len));
	                }
	                if(entry.getName().endsWith(".rptdic")){
	                	
	                	dataObject = JSON.parseObject(sb.toString().trim() , DataDic.class);
	                	executeImportCommand(dataObject , command);
	                	
	                }
	                
	                if(entry.getName().endsWith(".task")){  	
	                	PublishedReport rpt =  JSON.parseObject(sb.toString().trim() , PublishedReport.class);
	                	rpt.setReportcontent(URLDecoder.decode(rpt.getReportcontent()));
	                	executeImportCommand(rpt , command);
	                	TaskInfo taskinfo = JSON.parseObject(rpt.getReportcontent(), TaskInfo.class);
	                	JobDetail job = taskinfo.getJob();
	                	executeImportCommand(job , command);
	                	count++;
	                	
	                }
	                inputStream.close(); 
	           } 
			   writeFile.close();
	           zf.close(); 
			}else{
				throw new Exception(LocalTools.getMessage("E_REPORT_10010019"));
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
//			throw e;
			e.printStackTrace();
			response.setContentType("text/html,charset=UTF-8") ;
			response.setCharacterEncoding("UTF-8") ;
			response.getOutputStream().write(e.getMessage().getBytes()) ;
		}finally{
			if(fTemp!=null){
				fTemp.delete();
			}
		}
		return count;
    }

    @SuppressWarnings("unchecked")
	private void executeImportCommand(Object dataObject , String command) throws Exception{
    	String id = BeanUtils.getProperty(dataObject, "id") ;
    	/**
    	 * 无论新增，修改，删除还是 停用，都需要先验证 ID是否存在
    	 */
    	int count = RivuDataContext.getService().getCountByCriteria(DetachedCriteria.forClass(dataObject.getClass()).add(Restrictions.eq("id", id))) ;
    	if("update" .equals(command) || "publish" .equals(command)){
    		if(count==1){
    			RivuDataContext.getService().updateIObject(dataObject);
    		}else{
    			RivuDataContext.getService().saveIObject(dataObject);
    			//throw new Exception(LocalTools.getMessage("E_REPORT_10010020")+":"+BeanUtils.getProperty(dataObject, "name")+","+dataObject.getClass());
    		}
    	}else if("delete" .equals(command)){
    		if(count==1){
    			RivuDataContext.getService().deleteIObject(dataObject);
    		}else{
    			//throw new Exception(LocalTools.getMessage("E_REPORT_10010022")+":"+BeanUtils.getProperty(dataObject, "name")+","+dataObject.getClass());
    		}
    	}else if("unavailable" .equals(command)){
    		if(count==1){
    			/**
    			 * 将状态变为不可用
    			 */
    			if(BeanUtils.getProperty(dataObject, "status")!=null){
    				BeanUtils.setProperty(dataObject, "status", "unavailable");
        			RivuDataContext.getService().updateIObject(dataObject);
    			}
    			
    		}else{
    			//throw new Exception(LocalTools.getMessage("E_REPORT_10010023")+":"+BeanUtils.getProperty(dataObject, "name")+","+dataObject.getClass());
    		}
    	}else if("patch" .equals(command)){
    		if(count==1){
    			RivuDataContext.getService().updateIObject(dataObject);
    		}else{
    			//throw new Exception(LocalTools.getMessage("E_REPORT_10010024")+":"+BeanUtils.getProperty(dataObject, "name")+","+dataObject.getClass());
    		}
    	}
    }
}
